package com.jin.webvideo.videoCache;

import com.jin.webvideo.base.SpringBeanGetter;
import com.jin.webvideo.base.util.CollectionsUtil;
import com.jin.webvideo.entity.Cache;
import com.jin.webvideo.mapper.CacheMapper;
import com.jin.webvideo.service.CacheService;
import com.jin.webvideo.util.cloneUtil.CloneUtil;
import com.jin.webvideo.util.sys.SystemUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.ServletContextAware;

import javax.servlet.ServletContext;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

@Component
public class CacheExecutor implements ServletContextAware {

    @Autowired
    private CacheMapper cacheMapper;
    @Autowired
    private CachesPropertites propertites;

    private long validSpace = -100;
    private static ExecutorService executorService = null;
    public ExecutorService executor(){
        if (null == executorService){
            synchronized (CacheExecutor.class){
                if (null == executorService){
                    CacheThread.setFailRange(propertites.getAllowFailure());
                    executorService = Executors.newFixedThreadPool( propertites.getThreadCount() );
                }
            }
        }
        return executorService;
    }

    /**
     * 提交缓存任务
     * @param source 缓存的路径
     * @param cache
     * @param header 缓存需要的http headers
     */
    public void submit(String source, Cache cache, Map<String,String>header){
        cache = CloneUtil.clone(cache);
        // 重设cache location
        cache.setLocation(cacheLocation(cache));
        CacheService cacheService = SpringBeanGetter.getBean(CacheService.class);
        if (cacheService != null) {
            executor().submit(new CacheThread(cacheService, source, cache, header));
        }
    }

    /**
     * 申请空间，不足时删除旧的文件
     * @param size
     * @return
     */
    public boolean allocated(long size){
        // 分配size空间之后的余量
        long restSize = validSpace - size;
        if (restSize >= 0){
            return true;
        }
        List<Cache> cacheList = cacheMapper.listCanplay();
        for (Cache cache : cacheList){
            // 否则删除一个文件，释放其空间，更新缓存状态
            restSize = restSize + cache.getFileSize();
            String path = cacheLocation(cache);
            SystemUtil.deleteFile(new File(path) );
            cacheMapper.updateStatus(cache.getUrl(), Cache.STATUS_DEL);
            // 存在空余
            if (restSize >= 0){
                return true;
            }
        }
        return false;
    }

    /**
     * 获取本地缓存路径
     * @param cache
     * @return
     */
    public String cacheLocation(Cache cache){
        return propertites.saveLocation() + cache.getLocation() + "/";
    }

    /**
     * 获取缓存的真实访问路径
     * @param cache
     * @return
     */
    public String visitedUrl(Cache cache){
        return String.format("%s/%s/%s", propertites.getPrefix(), cache.getLocation(), cache.getFileName());
    }

    /**
     * 判断缓存文件是否本地已存在
     * @param cache
     * @return
     */
    public boolean exists(Cache cache){
        if (null == cache){
            return false;
        }
        String path = cacheLocation(cache);
        return new File(path).exists();
    }

    @Override
    public void setServletContext(ServletContext servletContext) {
        File file = new File(propertites.saveLocation());
        File[] files = file.listFiles();
        List<File> fileList = Arrays.asList(files);
        // 过滤掉非文件的文件
        fileList = fileList.stream().filter(temp -> temp.isDirectory()).collect(Collectors.toList());
        List<Cache> caches = cacheMapper.listCanplay();
        List<String> cacheNames = CollectionsUtil.convert(caches, accept -> accept.getLocation());
        // 只保留文件名
        List<String> fileNames = CollectionsUtil.convert(fileList, accept -> accept.getName());

        // 求交集
        cacheNames.retainAll(fileNames);
        // 删除表中不存在但实际存在缓存数据
        for (File temp : fileList){
            String name = temp.getName();
            if (!cacheNames.contains(name)){
                SystemUtil.deleteFile(temp);
                cacheNames.remove(name);
            }
        }
        // 删除表中存在但实际不存在的 表数据
        for (Cache cache : caches){
            if (!cacheNames.contains(cache.getLocation())){
                cacheMapper.updateStatus(cache.getUrl(), Cache.STATUS_DEL);
            }
        }
        // 初始化剩余空间
        init();
    }
    private void init(){
        long used = SystemUtil.fileSize(propertites.saveLocation());
        validSpace = propertites.getCacheSize() - used;
        System.out.println(String.format("rest space is %.2fMB", validSpace/1048576.0));
    }
}
